package systemInformation;

import java.util.ArrayList;
import java.util.Hashtable;

import java.util.List;

import org.snmp4j.smi.IpAddress;

import features.SNMPClient;
import features.SNMPException;
import features.SNMPSession;
import features.SNMPValue;


public class HostInfo {

	private final static String IP_ROUTE_DESTINATION_OID = "1.3.6.1.2.1.4.21.1.1";
	private final static String IP_ROUTE_NEXT_HOP_OID = "1.3.6.1.2.1.4.21.1.7";
	private final static String IP_AD_ENTR_ADDR = "1.3.6.1.2.1.4.20.1.1";
	private final static String SYSTEM_NAME_OID = "1.3.6.1.2.1.1.5";
	private SNMPSession session = null;

	/**
	 * Inizializza una sessione con l'indirizzo <code>ipAddress</code>.
	 * 
	 * @param ipAddress
	 *            l'indirizzo con cui si desidera comunicare..
	 * @throws SNMPException
	 *             se non riesce a comunicare con l'indirizzo utilizzando il
	 *             protocollo SNMP
	 */
	public HostInfo(IpAddress ipAddress) throws SNMPException {

		session = SNMPClient.startSession(SNMPClient.VERSION_2C);
		session.init(ipAddress.toString(), SNMPClient.DEFAULT_PORT_STRING,
				SNMPClient.DEFAULT_COMMUNITY);

	}

	/**
	 * Serve a costruire l'intera tabella d routing.
	 * 
	 * @return la lista di tutti i destinatari presenti nella tabella di routing
	 *         oppure null se si verifica un'eccezzione
	 */
	@SuppressWarnings("unchecked")
	private ArrayList<String> getAllDestinationHost() {
		ArrayList<String> destinations = null;

		// Ritorna una lista di ipRouteEntry
		List routeDestination;
		try {
			routeDestination = session.getColumn(IP_ROUTE_DESTINATION_OID);
			if (routeDestination.size() > 0) {
				destinations = new ArrayList<String>(routeDestination.size());
				for (int i = 0; i < routeDestination.size(); i++) {
					destinations.add(routeDestination.get(i).toString());
				}
			}

		} catch (SNMPException e) {

		}

		return destinations;

	}

	/**
	 * Serve a costruire l'intera tabella d routing.
	 * 
	 * @return la lista di tutti i nextHop presenti nella tabella di routing
	 *         (anche se duplicati)
	 * 
	 * oppure null se si verifica un'eccezione
	 */
	@SuppressWarnings("unchecked")
	private ArrayList<String> getAllNextHop() {
		ArrayList<String> nextHops = null;

		try {
			// Ritorna una lista di ipRouteEntry
			List nextHopRouteList = session.getColumn(IP_ROUTE_NEXT_HOP_OID);
			if (nextHopRouteList.size() > 0) {
				nextHops = new ArrayList<String>(nextHopRouteList.size());
				for (int i = 0; i < nextHopRouteList.size(); i++) {
					nextHops.add(nextHopRouteList.get(i).toString());
				}
			}

		} catch (SNMPException e) {

		}

		return nextHops;
	}

	/**
	 * Ritorna la tabella di routing (destinatario-next_hop) eliminando le righe
	 * duplicate.
	 * 
	 * @param host
	 *            l'host di cui si desidera ottenere la tabella di routing
	 * @return una mappa destinatario-next_hop dell'host.
	 */
	public Hashtable<String, String> getRouteTable() {

		Hashtable<String, String> routingHash = new Hashtable<String, String>();

		ArrayList<String> allNextHop = getAllNextHop();
		ArrayList<String> allDestination = getAllDestinationHost();

		if (allNextHop != null && allDestination != null
				&& allNextHop.size() == allDestination.size()) {
			int size = allNextHop.size();
			for (int i = 0; i < size; i++) {
				String dest = allDestination.get(i);
				String nextHop = allNextHop.get(i);
				if (!routingHash.containsKey(dest)
						&& !routingHash.contains(nextHop)) {
					routingHash.put(dest, nextHop);
				}
			}

		}

		return routingHash;
	}

	/**
	 * Ritorna la lista di tutte le interfacce dell'host.
	 * 
	 * @return la lista di tutte le interfacce dell'host o null se si verifica
	 *         un errore.
	 */
	public ArrayList<IpAddress> getAllInterfaces() {
		ArrayList<IpAddress> interfacesList = null;
		try {
			List interfaces = session.getColumn(IP_AD_ENTR_ADDR);
			interfacesList = new ArrayList<IpAddress>();
			for (int i = 0; i < interfaces.size(); i++) {
				SNMPValue value=(SNMPValue)interfaces.get(i);
				interfacesList.add(new IpAddress(value.toString() ));
			}
		} catch (SNMPException e) {
		}

		return interfacesList;
	}

	/**
	 * Ritorna il nome dell'host
	 * 
	 * @return il nome dell'host o null se si verifica un errore.
	 */
	public String getHostName() {
		String hostName = null;
		try {
			SNMPValue value = session.getNextValue(SYSTEM_NAME_OID);
			hostName = value.toString();
		} catch (SNMPException e) {
		}
		return hostName;
	}

	/**
	 * @return la lista dei next_hop con i duplicati eliminati
	 */
	@SuppressWarnings("unchecked")
	public ArrayList<IpAddress> getNextHops() {
		ArrayList<IpAddress> nextHops = null;

		try {

			List nextHopRouteList = session.getColumn(IP_ROUTE_NEXT_HOP_OID);
			if (nextHopRouteList.size() > 0) {
				nextHops = new ArrayList<IpAddress>();
				for (int i = 0; i < nextHopRouteList.size(); i++) {
					SNMPValue value = (SNMPValue) nextHopRouteList.get(i);
					IpAddress nextHop = (IpAddress) IpAddress.parse(value
							.toString());
					if (nextHop != null && !nextHops.contains(nextHop)) {
						nextHops.add(nextHop);
					}
				}
			}

		} catch (SNMPException e) {

		}
		return nextHops;
	}
}
